package cn.com.franke.collections;

import cn.com.franke.collections.ext.AddLoggingList;
import com.google.common.base.*;
import com.google.common.base.Optional;
import com.google.common.collect.*;
import com.google.common.primitives.Ints;
import org.junit.Test;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by liuzh on 2017/4/29.
 */
public class CollectionUtilsTest {

    //静态工厂方法
    @Test
    public void test1() {
        Person p1 = new Person("man", 15);
        Person p2 = new Person("woman", 16);
        //Lists
        List<Person> personList = Lists.newArrayList();//推断范型的静态工厂方法
        personList = new ArrayList<>();
        personList = Lists.newArrayList(p1, p2);//初始化时就指定起始元素
        personList = Lists.newArrayListWithCapacity(10);//初始化大小
        personList = Lists.newArrayListWithExpectedSize(10);//预估大小
        List<Person> personList1 = Lists.newLinkedList();
        List<Person> personList2 = Lists.newCopyOnWriteArrayList();
        //Sets --> Set,SortedSet
        Set<Person> personSet = Sets.newHashSet();
        personSet = new HashSet<>();
        personSet = Sets.newHashSet(p1, p2);
        personSet = Sets.newHashSetWithExpectedSize(3);
        Ordering<Person> ordering = Ordering.natural().onResultOf(new Function<Person, Comparable>() {
            @Override
            public Comparable apply(Person person) {
                return person.age;
            }
        });
        SortedSet<Person> personSortedSet = Sets.newTreeSet(ordering);
        //Maps --> Map,SortedMap
        Map<String, Person> personLinkedHashMap = Maps.newLinkedHashMap();
        SortedMap<String, Person> personSortedMap = Maps.newTreeMap();
        BiMap<Integer, String> biMap = HashBiMap.create();//BiMapzij提供静态工厂方法
        //Queues --> Queue
        Queue<Person> personQueue = Queues.newArrayBlockingQueue(10);
        Queue<Person> personQueue1 = Queues.newLinkedBlockingQueue();
        //Multisets
        Multiset<Person> hashMultiset = HashMultiset.create();
        //Multimaps
        Multimap<String, Person> multiMap = HashMultimap.create();
        //Tables
        Table<String, String, Person> personTable = HashBasedTable.create();
    }

    //Iterables
    @Test
    public void test2() {
        Person p1 = new Person("man", 15);
        Person p2 = new Person("woman", 16);
        Set<Person> personSet = Sets.newLinkedHashSet();
        personSet.add(p1);
        personSet.add(p2);
        Person lastAdded = Iterables.getLast(personSet);
        Person theElement = Iterables.getOnlyElement(personSet);//如果personSet不是单元素集，就会出错了！
        Iterable<Integer> concatenated = Iterables.concat(
                Ints.asList(1, 2, 3),
                Ints.asList(4, 5, 6)); // concatenated包括元素 1, 2, 3, 4, 5, 6
    }

    //Lists,Sets,Maps,Multisets,Multimaps,Tables
    @Test
    public void test3() {
        List countUp = Ints.asList(1, 2, 3, 4, 5);
        List countDown = Lists.reverse(countUp); // {5, 4, 3, 2, 1}
        List<List> parts = Lists.partition(countUp, 2);//{{1,2}, {3,4}, {5}}

        Set<String> wordsWithPrimeLength = ImmutableSet.of("one", "two", "three", "six", "seven", "eight");
        Set<String> primes = ImmutableSet.of("two", "three", "five", "seven");
        Sets.SetView<String> setsUnion = Sets.union(wordsWithPrimeLength, primes);//合集
        Sets.SetView<String> setsDiff = Sets.difference(wordsWithPrimeLength, primes);//差集
        Sets.SetView<String> intersection = Sets.intersection(primes, wordsWithPrimeLength);//交集
        Sets.SetView<String> setsSymDiff = Sets.symmetricDifference(primes, wordsWithPrimeLength);//对称差集
        // intersection包含"two", "three", "seven"
        intersection.immutableCopy();//可以使用交集，但不可变拷贝的读取效率更高
        Set<String> cpSet = Sets.newHashSet();
        intersection.copyInto(cpSet);//拷贝
        Set<String> animals = ImmutableSet.of("gerbil", "hamster");
        Set<String> fruits = ImmutableSet.of("apple", "orange", "banana");
        Set<List<String>> product = Sets.cartesianProduct(animals, fruits);//笛卡儿积
// {{"gerbil", "apple"}, {"gerbil", "orange"}, {"gerbil", "banana"},
//  {"hamster", "apple"}, {"hamster", "orange"}, {"hamster", "banana"}}
        Set<Set<String>> animalSets = Sets.powerSet(animals);//子集的集合
// {{}, {"gerbil"}, {"hamster"}, {"gerbil", "hamster"}}

        List<String> strings = ImmutableList.of("apple", "orange", "banana");
        try {
            ImmutableMap<Integer, String> stringsByIndex = Maps.uniqueIndex(strings,
                    new Function<String, Integer>() {
                        public Integer apply(String string) {
                            return string.length();
                        }
                    });
        } catch (Exception e) {
            ImmutableListMultimap<Integer, String> stringsByIndex1 = Multimaps.index(strings, new Function<String, Integer>() {
                public Integer apply(String string) {
                    return string.length();
                }
            });
        }
        Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3);
        Map<String, Integer> right = ImmutableMap.of("b", 2, "c", 2, "e", 3);
        MapDifference<String, Integer> diff = Maps.difference(left, right);
        System.out.println(diff.entriesInCommon()); // {"b" => 2}
        System.out.println(diff.entriesDiffering()); // {"b" => 2}
        System.out.println(diff.entriesOnlyOnLeft()); // {"a" => 1}
        System.out.println(diff.entriesOnlyOnRight()); // {"d" => 5}

        Multiset<String> multiset1 = HashMultiset.create();
        multiset1.add("a", 2);
        Multiset<String> multiset2 = HashMultiset.create();
        multiset2.add("a", 5);
        System.out.println(multiset1.containsAll(multiset2)); //返回true；因为包含了所有不重复元素，
        //虽然multiset1实际上包含2个"a"，而multiset2包含5个"a"
        System.out.println(Multisets.difference(multiset1, multiset2)); // returns false
        System.out.println(Multisets.containsOccurrences(multiset1, multiset2)); // returns false
        System.out.println(Multisets.removeOccurrences(multiset2, multiset1));
        System.out.println(Multisets.retainOccurrences(multiset2, multiset1));
        System.out.println(multiset2.remove("a", 3));//删除指定数目的a,返回multiset2删除前的数目
        System.out.println(multiset2.remove("a")); // 默认删除1个a
        System.out.println(multiset2.removeAll(multiset1));//multiset2移除所有"a"，虽然multiset1只有2个"a"
        System.out.println(multiset2.isEmpty()); // returns true
        Multiset<String> multiset = HashMultiset.create();
        multiset.add("a", 3);
        multiset.add("b", 5);
        multiset.add("c", 1);
        ImmutableMultiset highestCountFirst = Multisets.copyHighestCountFirst(multiset);//highestCountFirst，包括它的entrySet和elementSet，按{"b", "a", "c"}排列元素
        Multiset unmodifiableView = Multisets.unmodifiableMultiset(multiset);
//        Multiset unmodifiableSortedView = Multisets.unmodifiableSortedMultiset(multiset);

        ImmutableSet digits = ImmutableSet.of("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine");
        Function<String, Integer> lengthFunction = new Function<String, Integer>() {
            public Integer apply(String string) {
                return string.length();
            }
        };
        ImmutableListMultimap<Integer, String> digitsByLength = Multimaps.index(digits, lengthFunction);
        System.out.println(digitsByLength);
        ArrayListMultimap<String, Integer> multimap = ArrayListMultimap.create();
        multimap.putAll("b", Ints.asList(2, 4, 6));
        multimap.putAll("a", Ints.asList(4, 2, 1));
        multimap.putAll("c", Ints.asList(2, 5, 3));
        TreeMultimap<Integer, String> inverse = Multimaps.invertFrom(multimap, TreeMultimap.create());//注意我们选择的实现，因为选了TreeMultimap，得到的反转结果是有序的
        Map<String, Integer> map = ImmutableMap.of("a", 1, "b", 1, "c", 2);
        SetMultimap<String, Integer> multimap1 = Multimaps.forMap(map);
// multimap：["a" => {1}, "b" => {1}, "c" => {2}]
        Multimap<Integer, String> inverse1 = Multimaps.invertFrom(multimap1, HashMultimap.create());
// inverse：[1 => {"a","b"}, 2 => {"c"}]
        ListMultimap<String, Integer> myMultimap = Multimaps.newListMultimap(
                Maps.<String, Collection<Integer>>newTreeMap(),
                new Supplier<LinkedList<Integer>>() {
                    public LinkedList get() {
                        return Lists.newLinkedList();
                    }
                });
        myMultimap.putAll("a", Ints.asList(1, 2, 3, 4));
        myMultimap.putAll("b", Ints.asList(3, 5, 6));

//Tables
        // 使用LinkedHashMaps替代HashMaps
        Table<String, Character, Integer> table = Tables.newCustomTable(
                Maps.<String, Map<Character, Integer>>newLinkedHashMap(),
                new Supplier<Map<Character, Integer>>() {
                    public Map<Character, Integer> get() {
                        return Maps.newLinkedHashMap();
                    }
                });
        table.put("a", 'A', 1);
        table.put("a", 'B', 2);
        table.put("b", 'A', 3);
        table.put("c", 'B', 4);
        System.out.println(table);
        System.out.println(Tables.transpose(table));//行列转换

    }

    @Test
    public void test4() {
        Person p1 = new Person("liu", 18, new Date());
        Person p2 = new Person("wang", 17, new Date());
        Person p3 = new Person("li", 19, new Date());
        HashSet<Person> set = Sets.newHashSet(p1, p2, p3);

        Collection<PersonPo> result2 = Collections2.transform(set, new Function<Person, PersonPo>() {
            @Override
            public PersonPo apply(Person f) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String date = f.getDate() == null ? "" : sdf.format(f.getDate());
                return new PersonPo(f.name, f.getAge(), date);
            }
        });

        result2.forEach(System.out::println);
        Collection<Person> result3 = Collections2.filter(set, new Predicate<Person>() {
            @Override
            public boolean apply(Person person) {
                return person.getAge() < 18;
            }
        });
        result3.forEach(System.out::println);
        Collection<List<Person>> result4 = Collections2.orderedPermutations(set, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return Ints.compare(o1.getAge(), o2.getAge());
            }
        });
        result4.forEach(System.out::println);//所有排序方式
        Collection<List<Person>> result5 = Collections2.permutations(set);
        result5.forEach(System.out::println);//所有排序方式
    }

    //Forwarding装饰器/PeekingIterator(事先窥视[peek()]到下一次调用next()返回的元素)/AbstractIterator(实现你自己的Iterator)
    @Test
    public void test5() {
        AddLoggingList<String> loggingList = AddLoggingList.create();
        loggingList.add("liu");
        loggingList.add("hhh");
        List<String> result = Lists.newArrayList();

        PeekingIterator<String> iter = Iterators.peekingIterator(loggingList.iterator());
        while (iter.hasNext()) {
            String current = iter.next();
//            String peek = iter.peek();
            while (iter.hasNext() && iter.peek().equals(current)) {
                //跳过重复的元素
                iter.next();
            }
            result.add(current);
        }
        result.add("");
        result.add(null);
        Iterator<String> noNullIter = skipNulls(result.iterator());
        while (null != noNullIter && noNullIter.hasNext()) {
            System.out.println("value:"+noNullIter.next());
        }
//        有一些迭代器用其他方式表示会更简单。AbstractSequentialIterator 就提供了表示迭代的另一种方式。
//        注意，你必须额外传入一个初始值，或者传入null让迭代立即结束。因为computeNext(T)假定null值意味着迭代的末尾——AbstractSequentialIterator不能用来实现可能返回null的迭代器。
        Iterator<Integer> powersOfTwo = new AbstractSequentialIterator<Integer>(1) { // 注意初始值1!
            protected Integer computeNext(Integer previous) {
                return (previous == 1 << 30) ? null : previous * 2;
            }
        };

    }

    public static Iterator<String> skipNulls(final Iterator<String> in) {
        //注意：AbstractIterator继承了UnmodifiableIterator，所以禁止实现remove()方法。如果你需要支持remove()的迭代器，就不应该继承AbstractIterator。
        return new AbstractIterator<String>() {
            protected String computeNext() {
                while (in.hasNext()) {
                    String s = in.next();
                    if (s != null) {
                        return s;
                    }
                }
                return endOfData();//如果循环结束了也没有找到下一个值，请返回endOfData()表明已经到达迭代的末尾。
            }
        };
    }

    class Person {
        private String name;
        private int age;
        private Date date;

        Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        Person(String name, int age, Date date) {
            this.name = name;
            this.age = age;
            this.date = date;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public Date getDate() {
            return date;
        }

        public void setDate(Date date) {
            this.date = date;
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", date=" + date +
                    '}';
        }
    }

    class PersonPo {
        private String name;
        private int age;
        private String date;

        PersonPo(String name, int age, String date) {
            this.name = name;
            this.age = age;
            this.date = date;
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", date=" + date +
                    '}';
        }
    }


}

